package com.xunua.myaudioandvideolearning.h264Packaging

import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
import android.media.MediaCodec
import android.media.MediaCodec.CONFIGURE_FLAG_ENCODE
import android.media.MediaCodecInfo
import android.media.MediaFormat
import android.media.projection.MediaProjection
import android.util.Log
import java.lang.Exception

/**
 * @author: linxunyou
 * @description:
 * @date :2022/5/6 15:48
 **/
private const val TAG = "H264Encoder"
class H264Encoder(
    //数据源(录屏、直播、摄像头等)           将录屏数据投放到Surface    数据源可以更换
    var mediaProjection: MediaProjection,
    //输出文件
//    var
) : Thread()
{
    //编码器       从Surface中去取
    var mediaCodec: MediaCodec?=null
    init {
        var width=1280
        var height=720
        //编码，需要提供基本信息     参考sps pps为准           配置帧：sps pps   基础配置帧：pps 全量配置帧：sps
        var format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height)
        try {
            mediaCodec= MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC)
            format.setInteger(MediaFormat.KEY_FRAME_RATE,   20)//帧率，一秒钟20帧
            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,30)//固定的I帧间隔，30帧出现一个I帧
            format.setInteger(MediaFormat.KEY_BIT_RATE,width*height)//码率，编码质量。越高代表质量越清晰
            format.setInteger(MediaFormat.KEY_COLOR_FORMAT,MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)//数据来源
            //flag: 编码标志位，代表这个任务是用来编码h264
            mediaCodec?.configure(format,null,null,CONFIGURE_FLAG_ENCODE)
            //提供场地---创建虚拟surface
            var surface = mediaCodec?.createInputSurface()
            //mediaProjection输出数据    -----屏幕-------》 虚拟的屏幕
            //可以将录频的数据显示到surface，也可以将录屏的数据存储到虚拟的surface中不显示在屏幕上
            //@params:dpi   1dpi显示多少个像素
            mediaProjection.createVirtualDisplay(//进行绑定，将录屏数据绑定到surface中
                "啦啦",width,height,2,DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,surface,null,null
            )

        }catch (e:Exception){
            Log.e(TAG, "报错了: $e")
        }

    }

    override fun run() {
        super.run()
        mediaCodec?.start()
        val bufferInfo = MediaCodec.BufferInfo()
        while (true){
            //直接拿到输出，不用管输入，输入已经实现了
            val outIndex = mediaCodec?.dequeueOutputBuffer(bufferInfo, 1000 * 10)?:-1
            if (outIndex>=0){
                //拿到编码后的数据
                var outputBuffer = mediaCodec?.getOutputBuffer(outIndex)
                var byteArray = ByteArray(bufferInfo.size)
                outputBuffer?.get(byteArray)//将容器的outputBuffer 内部的数据  转移到byteArray中
                FileUtils.writeBytes(byteArray)
                FileUtils.writeContent(byteArray)
                mediaCodec?.releaseOutputBuffer(outIndex,false)
            }
        }
    }
}